﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpPcap;
using SharpPcap.LibPcap;
using System.Net.NetworkInformation;


namespace Derrick.AttackTest
{
    public class SpoofService
    {

        //custom events
        public event EventHandler<SelectDeviceEventArgs> RaiseSelectDeviceEvent;
        public event EventHandler<ListeningToDeviceEventArgs> RaiseListeningToDeviceEvent;

        private string _phonyIpAddress;
        private string _destinationIpAddress;
        private ushort _sourcePort;
        private ushort _destinationPort;

        public string PhonyIpAddress
        {
            get { return _phonyIpAddress; }
            set { _phonyIpAddress = value; }
        }

        public string DestinationIpAddress
        {
            get { return _destinationIpAddress; }
            set { _destinationIpAddress = value; }
        }

        public ushort SourcePort
        {
            get { return _sourcePort; }
            set { _sourcePort = value; }
        }

        public ushort DestinationPort
        {
            get { return _destinationPort; }
            set { _destinationPort = value; }
        }

        public SpoofService()
        {


        }

        public void StartSpoofing()
        {

            _phonyIpAddress = SharedStorage.Instance.PhonyIpAddress;
            _sourcePort = SharedStorage.Instance.SourcePort;
            _destinationIpAddress = SharedStorage.Instance.DestinationIpAddress;
            _destinationPort = SharedStorage.Instance.DestinationPort;

            // Print SharpPcap version
            string ver = SharpPcap.Version.VersionString;
            SharedStorage.Instance.AddDebugInfo("Spoofing", "SharpPcap " + ver + ", Spoofing.", String.Empty, String.Empty);

            // Retrieve the device list
            var devices = CaptureDeviceList.Instance;

            // If no devices were found print an error
            if (devices.Count < 1)
            {
                SharedStorage.Instance.AddDebugInfo("Spoofing", "No devices for spoofing found.", String.Empty, String.Empty);
                return;
            }

            SharedStorage.Instance.AddDebugInfo("Spoofing", "The following devices are available on this machine:", String.Empty, String.Empty);
            SharedStorage.Instance.AddDebugInfo("Spoofing", "----------------------------------------------------", String.Empty, String.Empty);

            int i = 0;

            // Print out the available devices
            foreach (var dev in devices)
            {
                SharedStorage.Instance.AddDebugInfo("Spoofing", i + ") " + dev.Description, String.Empty, String.Empty);
                SharedStorage.Instance.AddDeviceForCapturing(i, dev.Description);
                i++;
            }
            SharedStorage.Instance.AddDebugInfo("Spoofing", i + ") Read packets from offline pcap file", String.Empty, String.Empty);

            //Replace with Window.
            //Console.Write("-- Please choose a device to capture: ");
            SelectDevice selectDeviceWindow = new SelectDevice();
            selectDeviceWindow.SetDataSource(SharedStorage.Instance.DevicesForCapturing);
            selectDeviceWindow.ShowDialog();
            //onRaiseSelectDeviceEvent(new SelectDeviceEventArgs());

            //var choice = int.Parse(Console.ReadLine());
            //int[] choices = new int[SharedStorage.Instance.DevicesForCapturing.Count];


            ICaptureDevice device = null;
            foreach (schemaAttack.DevicesForCapturingRow deviceRow in SharedStorage.Instance.DevicesForCapturing)
            {
                if (deviceRow.Selected)
                {
                    //Console.Write("-- Please enter an input capture file name: ");
                    //string capFile = Console.ReadLine();
                    //device = new CaptureFileReaderDevice(deviceRow.CaptureFile);
                    device = devices[deviceRow.Device_ID];
                    break;
                }
                //else
                //{
                ////    device = devices[choice];
                //    device = new CaptureFileReaderDevice(deviceRow.CaptureFile);
                //}
            }
            //Register our handler function to the 'packet arrival' event
            device.OnPacketArrival +=
                new PacketArrivalEventHandler(device_OnPacketArrival);

            // Open the device for capturing
            device.Open();

            //Console.WriteLine();
            //Console.WriteLine
            //    ("-- Listening on {0}, hit 'Ctrl-C' to exit...",
            //    device.Description);
            ListeningToDeviceEventArgs args = new ListeningToDeviceEventArgs();
            args.Message = "-- Listening on " + device.Description + ".";
            onListeningToDeviceEvent(args);

            // Start capture 'INFINTE' number of packets
            device.Capture();

            // Close the pcap device
            // (Note: this line will never be called since
            //  we're capturing infinite number of packets
            device.Close();

        }

        private void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
            var packet = PacketDotNet.Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
            if (packet is PacketDotNet.EthernetPacket)
            {
                var eth = ((PacketDotNet.EthernetPacket)packet);
                Console.WriteLine("Original Eth packet: " + eth.ToString());

                //Manipulate ethernet parameters
                eth.SourceHwAddress = PhysicalAddress.Parse("00-11-22-33-44-55");
                eth.DestinationHwAddress = PhysicalAddress.Parse("00-99-88-77-66-55");

                var ip = PacketDotNet.IpPacket.GetEncapsulated(packet);
                if (ip != null)
                {
                    Console.WriteLine("Original IP packet: " + ip.ToString());

                    //manipulate IP parameters
                    //ip.SourceAddress = System.Net.IPAddress.Parse("1.2.3.4");
                    ip.SourceAddress = System.Net.IPAddress.Parse(_phonyIpAddress);
                    //ip.DestinationAddress = System.Net.IPAddress.Parse("44.33.22.11");
                    ip.DestinationAddress = System.Net.IPAddress.Parse(_destinationIpAddress);
                    ip.TimeToLive = 11;

                    var tcp = PacketDotNet.TcpPacket.GetEncapsulated(packet);
                    if (tcp != null)
                    {
                        Console.WriteLine("Original TCP packet: " + tcp.ToString());

                        //manipulate TCP parameters
                        //tcp.SourcePort = 9999;
                        //tcp.DestinationPort = 8888;
                        tcp.SourcePort = _sourcePort;
                        tcp.DestinationPort = _destinationPort;
                        tcp.Syn = !tcp.Syn;
                        tcp.Fin = !tcp.Fin;
                        tcp.Ack = !tcp.Ack;
                        tcp.WindowSize = 500;
                        tcp.AcknowledgmentNumber = 800;
                        tcp.SequenceNumber = 800;
                    }

                    var udp = PacketDotNet.UdpPacket.GetEncapsulated(packet);
                    if (udp != null)
                    {
                        Console.WriteLine("Original UDP packet: " + udp.ToString());

                        //manipulate UDP parameters
                        //udp.SourcePort = 9999;
                        //udp.DestinationPort = 8888;
                        udp.SourcePort = _sourcePort;
                        udp.DestinationPort = _destinationPort;
                    }
                }

                Console.WriteLine("Manipulated Eth packet: " + eth.ToString());
            }
        }

        protected virtual void onRaiseSelectDeviceEvent(SelectDeviceEventArgs args)
        {
            EventHandler<SelectDeviceEventArgs> handler = RaiseSelectDeviceEvent;
            if (handler != null)
            {
                handler(this, args);
            }
        }

        protected virtual void onListeningToDeviceEvent(ListeningToDeviceEventArgs args)
        {
            EventHandler<ListeningToDeviceEventArgs> handler = RaiseListeningToDeviceEvent;
            if (handler != null)
            {
                handler(this, args);
            }
        }

    }
}
